package com.wg.net.server.tcp;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.wg.net.NetConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollIoHandler;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioIoHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

/**
 * TCP服务器实现类，基于Netty框架，支持NIO/Epoll传输方式
 *
 * @author 少爷123
 */
public class TcpServer implements ITcpServer {
    private static final Log log = LogFactory.get();
    /**
     * Netty服务引导类
     */
    private final ServerBootstrap bootstrap;
    /**
     * 主线程组（监听连接）
     */
    private final EventLoopGroup bossGroup;
    /**
     * 工作线程组（处理连接）
     */
    private final EventLoopGroup workerGroup;
    /**
     * 服务器配置
     */
    private final NetConfig netConfig;
    /**
     * 服务端Channel（用于优雅关闭）
     */
    private Channel serverChannel;
    /**
     * 服务器启动状态标志
     */
    private volatile boolean isStarted = false;

    /**
     * 构造TCP服务器实例
     *
     * @param netConfig 服务器配置（不可为null）
     * @throws IllegalArgumentException 若配置参数无效
     */
    public TcpServer(NetConfig netConfig) {
        // 参数有效性校验
        if (netConfig == null) {
            throw new IllegalArgumentException("NetConfig不能为null");
        }
        if (netConfig.getWorkThreads() <= 0) {
            throw new IllegalArgumentException("工作线程数必须大于0");
        }
        if (netConfig.getLowWaterMark() < 0 || netConfig.getHighWaterMark() <= netConfig.getLowWaterMark()) {
            throw new IllegalArgumentException("写缓冲区水线参数无效（低水线需≥0，高水线需>低水线）");
        }

        this.bootstrap = new ServerBootstrap();
        this.netConfig = netConfig;

        // 初始化事件循环组
        if (Epoll.isAvailable()) {
            this.bossGroup = new MultiThreadIoEventLoopGroup(2, EpollIoHandler.newFactory());
            this.workerGroup = new MultiThreadIoEventLoopGroup(netConfig.getWorkThreads(), EpollIoHandler.newFactory());
            this.bootstrap.group(bossGroup, workerGroup) .channel(EpollServerSocketChannel.class);
        } else {
            this.bossGroup = new MultiThreadIoEventLoopGroup(2, NioIoHandler.newFactory());
            this.workerGroup = new MultiThreadIoEventLoopGroup( netConfig.getWorkThreads(), NioIoHandler.newFactory());
            this.bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class);
        }

        configureBootstrap();
    }

    /**
     * 配置ServerBootstrap（通道类型、处理器链、选项等）
     */
    private void configureBootstrap() {
        // 配置Socket参数（服务端）
        bootstrap.option(ChannelOption.SO_REUSEADDR, netConfig.isReuseAddr()) // 允许地址复用（避免端口占用问题）
                .option(ChannelOption.SO_BACKLOG, netConfig.getBacklogSize()) // 连接队列长度（从配置获取）
                .childOption(ChannelOption.TCP_NODELAY, netConfig.isTcpNoDelay()) // 禁用Nagle算法（减少小数据包延迟）
                .childOption(ChannelOption.SO_KEEPALIVE, netConfig.isKeepAlive()) // 启用TCP keep-alive（保持长连接）
                .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, // 写缓冲区水线（控制可写状态）
                        new WriteBufferWaterMark(netConfig.getLowWaterMark(), netConfig.getHighWaterMark()));

        // 初始化ChannelPipeline（连接建立时的处理器链）
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) {
                ChannelPipeline pipeline = ch.pipeline();
                // 1. 空闲状态检测（心跳机制）
                if (netConfig.getDisconnectTimeout() > 0) {
                    pipeline.addLast("idleStateHandler",
                            new IdleStateHandler(netConfig.getDisconnectTimeout(), 0, 0, TimeUnit.SECONDS));
                }
                // 2. 日志记录（记录原始入站/出站数据，调试用）
                if (netConfig.isLogActive()) {
                    pipeline.addLast("logger", new LoggingHandler(LogLevel.DEBUG));
                }
                // 3. 服务端处理器（处理连接生命周期、空闲超时、异常断开等逻辑）
                pipeline.addLast(new TcpServerHandler());
                // 4. 数据解码器（解析客户端请求）
                pipeline.addLast(new InitializeDecoder());
            }
        });
    }

    /**
     * 启动TCP服务器（监听指定端口）
     *
     * @throws RuntimeException 若启动失败（如端口被占用）
     */
    @Override
    public void start() {
        if (isStarted) {
            log.warn("TCP服务器已启动，无需重复操作");
            return;
        }

        int port = netConfig.getTcpPort();
        if (port <= 0) {
            return;
        }

        log.info("开始启动TCP服务器，监听端口：{}", port);
        try {
            // 绑定端口并同步等待（阻塞直到绑定完成）
            serverChannel = bootstrap.bind(port).sync().channel();
            log.info("TCP服务器启动成功，正在监听端口：{}", port);
            isStarted = true;
        } catch (InterruptedException e) {
            log.error("TCP服务器启动被中断", e);
            Thread.currentThread().interrupt(); // 恢复线程中断状态
            throw new RuntimeException("TCP服务器启动被中断", e);
        } catch (Exception e) {
            log.error("TCP服务器启动失败，端口：{}", port, e);
            throw new RuntimeException("TCP服务器启动失败，端口：" + port, e);
        }
    }

    /**
     * 优雅关闭TCP服务器（释放所有资源）
     */
    @Override
    public void stop() {
        if (!isStarted) {
            log.warn("TCP服务器未启动，无需关闭");
            return;
        }

        log.info("开始关闭TCP服务器...");
        isStarted = false;

        // 1. 关闭服务端Channel（停止接收新连接）
        if (serverChannel != null) {
            log.info("正在关闭服务端Channel...");
            serverChannel.close().addListener(future -> {
                if (future.isSuccess()) {
                    log.info("服务端Channel关闭成功");
                } else {
                    log.error("服务端Channel关闭失败，原因：{}", future.cause());
                }
            });
        }

        // 2. 优雅关闭线程组（停止处理现有连接）
        try {
            // 等待主线程组关闭（超时时间从配置获取）
            if (bossGroup.shutdownGracefully().await(netConfig.getShutdownTimeout(), TimeUnit.SECONDS)) {
                log.info("Boss线程组关闭成功");
            } else {
                log.warn("Boss线程组关闭超时（超时时间={}秒）", netConfig.getShutdownTimeout());
            }

            // 等待工作线程组关闭（超时时间从配置获取）
            if (workerGroup.shutdownGracefully().await(netConfig.getShutdownTimeout(), TimeUnit.SECONDS)) {
                log.info("工作线程组关闭成功");
            } else {
                log.warn("工作线程组关闭超时（超时时间={}秒）", netConfig.getShutdownTimeout());
            }
        } catch (InterruptedException e) {
            log.error("关闭过程中被中断", e);
            Thread.currentThread().interrupt(); // 恢复线程中断状态
        } finally {
            log.info("TCP服务器关闭完成");
        }
    }
}